package coupon.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import coupon.service.ICouponService;
import coupon.utils.SimpleRedisLock;
import common.model.result.Result;
import common.model.result.ResultCodeEnum;

import org.springframework.stereotype.Service;
import coupon.mapper.UserCouponMapper;
import coupon.mapper.CouponMapper;
import coupon.mapper.CouponUsageMapper;
import common.model.coupon.UserCoupon;
import common.model.coupon.Coupon;
import common.model.coupon.CouponUsage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.stream.Collectors;
import common.dto.coupon.CouponDTO;
import common.dto.coupon.CouponData;

import org.springframework.beans.BeanUtils;
import common.dto.coupon.UserCouponDTO;

import java.util.Set;
import org.springframework.transaction.annotation.Transactional;
import java.util.Map;

@Service
public class CouponServiceImpl implements ICouponService {

    @Autowired
    private UserCouponMapper userCouponMapper;

    @Autowired
    private CouponMapper couponMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    @Autowired
    private CouponUsageMapper couponUsageMapper;

    //查询所有可领取优惠券
    @Override
    public Result allCoupons(Long userId) {
        //查询所有可领取优惠券
        List<Coupon> coupons = couponMapper.selectList(new LambdaQueryWrapper<Coupon>()
                .eq(Coupon::getStatus, 1));
                
        // 查询用户已领取的优惠券
        List<UserCoupon> userCoupons = userCouponMapper.selectList(new LambdaQueryWrapper<UserCoupon>()
                .eq(UserCoupon::getUserId, userId));
        
        // 创建一个集合存储用户已领取的优惠券ID
        Set<Long> receivedCouponIds = userCoupons.stream()
                .map(UserCoupon::getCouponId)
                .collect(Collectors.toSet());
        
        // 将Coupon转换为CouponDTO
        List<CouponDTO> couponDTOList = coupons.stream().map(coupon -> {
            CouponDTO dto = new CouponDTO();
            // 使用BeanUtils复制属性
            BeanUtils.copyProperties(coupon, dto);
            
            // 判断用户是否已领取该优惠券
            boolean isReceived = receivedCouponIds.contains(coupon.getId());
            dto.setReceived(isReceived);
            
            return dto;
        }).collect(Collectors.toList());
        
        return Result.success(couponDTOList);
    }

    //获取结算页面的优惠券列表
    @Override
    public Result checkoutCoupons(Long userId) {
        //查询用户优惠券列表
        List<UserCoupon> userCoupons = userCouponMapper.selectList(new LambdaQueryWrapper<UserCoupon>()
                .eq(UserCoupon::getUserId, userId)
                .eq(UserCoupon::getStatus, 0));
        //转换为UserCouponDTO列表
        List<UserCouponDTO> userCouponDTOList = userCoupons.stream().map(userCoupon ->{
            UserCouponDTO dto = new UserCouponDTO();
            // 复制UserCoupon基本属性
            dto.setId(userCoupon.getId());
            dto.setUserId(userCoupon.getUserId());
            dto.setCouponId(userCoupon.getCouponId());
            dto.setCouponCode(userCoupon.getCouponCode());
            dto.setStatus(userCoupon.getStatus());
            dto.setObtainTime(userCoupon.getObtainTime());
            dto.setUsedTime(userCoupon.getUsedTime());
            dto.setExpireTime(userCoupon.getExpireTime());
            dto.setOrderNo(userCoupon.getOrderNo());
            //查询对应的优惠券信息
            Coupon coupon = couponMapper.selectById(userCoupon.getCouponId());
            if (coupon != null) {
                // 创建并设置CouponData
                CouponData couponData = new CouponData();
                couponData.setName(coupon.getName());
                couponData.setShopId(coupon.getShopId());
                couponData.setType(coupon.getType());
                couponData.setValue(coupon.getValue());
                couponData.setMinAmount(coupon.getMinAmount());
                couponData.setStackable(coupon.getStackable());
                dto.setCouponData(couponData);
            }
            return dto;
        }).collect(Collectors.toList());
        //返回结果
        return Result.success(userCouponDTOList);

    }

    //查询用户优惠券列表
    @Override
    public Result listCoupons(
            Long userId,
            Integer status,
            Integer page,
            Integer pageSize
        ) {
        // 分页查询 
        Page<UserCoupon> userCouponPage = new Page<>(page, pageSize);
        LambdaQueryWrapper<UserCoupon> queryWrapper = new LambdaQueryWrapper<UserCoupon>()
                .eq(UserCoupon::getUserId, userId)
                .eq(UserCoupon::getStatus, status);
        
        userCouponMapper.selectPage(userCouponPage, queryWrapper);
        
        // 转换为UserCouponDTO列表
        List<UserCouponDTO> userCouponDTOList = userCouponPage.getRecords().stream().map(userCoupon -> {
            UserCouponDTO dto = new UserCouponDTO();
            // 复制UserCoupon基本属性
            dto.setId(userCoupon.getId());
            dto.setUserId(userCoupon.getUserId());
            dto.setCouponId(userCoupon.getCouponId());
            dto.setCouponCode(userCoupon.getCouponCode());
            dto.setStatus(userCoupon.getStatus());
            dto.setObtainTime(userCoupon.getObtainTime());
            dto.setUsedTime(userCoupon.getUsedTime() != null ? userCoupon.getUsedTime() : null);
            dto.setExpireTime(userCoupon.getExpireTime());
            dto.setOrderNo(userCoupon.getOrderNo());
            
            // 查询对应的优惠券信息
            Coupon coupon = couponMapper.selectById(userCoupon.getCouponId());
            if (coupon != null) {
                // 创建并设置CouponData
                CouponData couponData = new CouponData();
                couponData.setName(coupon.getName());
                couponData.setType(coupon.getType());
                couponData.setValue(coupon.getValue());
                couponData.setMinAmount(coupon.getMinAmount());
                couponData.setStackable(coupon.getStackable());
                dto.setCouponData(couponData);
            }
            
            return dto;
        }).collect(Collectors.toList());
        
        // 创建新的分页对象
        Page<UserCouponDTO> dtoPage = new Page<>(userCouponPage.getCurrent(), userCouponPage.getSize(), userCouponPage.getTotal());
        dtoPage.setRecords(userCouponDTOList);
        
        return Result.success(dtoPage);
    }

    @Override
    public Result listShopCoupons(Long userId, Long shopId) {
        // 查询商铺优惠券列表
        List<Coupon> shopCoupons = couponMapper.selectList(new LambdaQueryWrapper<Coupon>()
                .eq(Coupon::getShopId, shopId));
        
        // 查询用户已领取的优惠券
        List<UserCoupon> userCoupons = userCouponMapper.selectList(new LambdaQueryWrapper<UserCoupon>()
                .eq(UserCoupon::getUserId, userId));
        
        // 创建一个集合存储用户已领取的优惠券ID
        Set<Long> receivedCouponIds = userCoupons.stream()
                .map(UserCoupon::getCouponId)
                .collect(Collectors.toSet());
        
        // 将Coupon转换为CouponDTO
        List<CouponDTO> couponDTOList = shopCoupons.stream().map(coupon -> {
            CouponDTO dto = new CouponDTO();
            // 使用BeanUtils复制属性
            BeanUtils.copyProperties(coupon, dto);
            
            // 判断用户是否已领取该优惠券
            boolean isReceived = receivedCouponIds.contains(coupon.getId());
            dto.setReceived(isReceived);
            
            return dto;
        }).collect(Collectors.toList());
        
        return Result.success(couponDTOList);
    }

    @Override
    public Result receiveCoupon(Long userId, Long couponId) {
        //查询优惠券
        Coupon coupon = couponMapper.selectById(couponId);
        //判断是否是秒杀券
        if(coupon.getType() == 2) {
            //执行秒杀券逻辑
            return seckillCoupon(userId, coupon);
        }
        //执行普通券的逻辑
        return CommonCoupon(userId, coupon);
    }

    public Result seckillCoupon(Long userId, Coupon coupon) {
        //1.判断秒杀是否开始
        if(coupon.getSeckillStart().isAfter(LocalDateTime.now())) {
            //没开始
            return Result.failure(ResultCodeEnum.FAIL, "秒杀尚未开始");
        }
        //3.判断秒杀是否已经结束
        if(coupon.getSeckillEnd().isBefore(LocalDateTime.now())) {
            //已经结束
            return Result.failure(ResultCodeEnum.FAIL, "秒杀已经结束");
        }
        //4.判断库存是否充足
        if(coupon.getTotalCount() < 1) {
            return Result.failure(ResultCodeEnum.FAIL, "库存不足");
        }
        //5.获取互斥锁
        //5.1.创建锁对象
        SimpleRedisLock lock = new SimpleRedisLock("order:" + userId, stringRedisTemplate);
        //5.2.获取锁
        boolean isLock = lock.tryLock(1200);
        //判断是否获取锁成功
        if(!isLock){
            //获取锁失败
            return Result.failure(ResultCodeEnum.FAIL, "不允许重复下单");
        }
        try {
            //6.判断用户是否已经抢购过
            Long count = userCouponMapper.selectCount(new LambdaQueryWrapper<UserCoupon>()
                    .eq(UserCoupon::getUserId, userId)
                    .eq(UserCoupon::getCouponId, coupon.getId()));
            if (count > 0) {
                return Result.failure(ResultCodeEnum.FAIL, "您已经抢购过该优惠券");
            }
            
            //7.扣减库存
            Coupon updateCoupon = new Coupon();
            updateCoupon.setTotalCount(coupon.getTotalCount() - 1);
            boolean success = couponMapper.update(updateCoupon, new LambdaQueryWrapper<Coupon>()
                    .eq(Coupon::getId, coupon.getId())
                    .gt(Coupon::getTotalCount, 0)) > 0;
            if (!success) {
                return Result.failure(ResultCodeEnum.FAIL, "库存不足");
            }
            
            //8.创建订单
            UserCoupon userCoupon = new UserCoupon();
            userCoupon.setUserId(userId);
            userCoupon.setCouponId(coupon.getId());
            userCoupon.setStatus(0);
            userCoupon.setCouponCode(coupon.getCouponCode());
            
            // 设置领取时间
            LocalDateTime now = LocalDateTime.now();
            userCoupon.setObtainTime(now);
            
            // 设置过期时间
            if (coupon.getValidityDays() != null && coupon.getValidityDays() > 0) {
                // 如果设置了领取后有效天数，则使用当前时间+有效天数
                userCoupon.setExpireTime(now.plusDays(coupon.getValidityDays()));
            } else {
                // 否则使用优惠券本身的结束时间
                userCoupon.setExpireTime(coupon.getEndTime());
            }
            
            userCouponMapper.insert(userCoupon);
            return Result.success(userCoupon.getId());
        } finally {
            //释放锁
            lock.unlock();
        }
    }

    public Result CommonCoupon(Long userId, Coupon coupon) {
        //1.判断优惠券状态
        if (coupon.getStatus() != 1) {
            return Result.failure(ResultCodeEnum.FAIL, "优惠券未发布或已停用");
        }
        
        //2.判断活动时间
        LocalDateTime now = LocalDateTime.now();
        if (coupon.getStartTime().isAfter(now)) {
            return Result.failure(ResultCodeEnum.FAIL, "优惠券活动未开始");
        }
        if (coupon.getEndTime().isBefore(now)) {
            return Result.failure(ResultCodeEnum.FAIL, "优惠券活动已结束");
        }
        
        //3.判断用户是否达到限领数量
        if (coupon.getPerUserLimit() != null && coupon.getPerUserLimit() > 0) {
            Long count = userCouponMapper.selectCount(new LambdaQueryWrapper<UserCoupon>()
                    .eq(UserCoupon::getUserId, userId)
                    .eq(UserCoupon::getCouponId, coupon.getId()));
            if (count >= coupon.getPerUserLimit()) {
                return Result.failure(ResultCodeEnum.FAIL, "已达到领取上限");
            }
        }
        
        //4.创建优惠券记录
        UserCoupon userCoupon = new UserCoupon();
        userCoupon.setUserId(userId);
        userCoupon.setCouponId(coupon.getId());
        userCoupon.setCouponCode(coupon.getCouponCode()); // 冗余存储优惠券编码
        userCoupon.setStatus(0); // 0表示未使用
        userCoupon.setObtainTime(now); // 设置领取时间
        
        // 设置过期时间
        if (coupon.getValidityDays() != null && coupon.getValidityDays() > 0) {
            // 如果设置了领取后有效天数，则使用当前时间+有效天数
            userCoupon.setExpireTime(now.plusDays(coupon.getValidityDays()));
        } else {
            // 否则使用优惠券本身的结束时间
            userCoupon.setExpireTime(coupon.getEndTime());
        }
        
        userCouponMapper.insert(userCoupon);
        return Result.success(userCoupon.getId());
    }

    @Override
    public Result couponList(Long userId) {
        // 查询用户所有优惠券
        List<UserCoupon> userCoupons = userCouponMapper.selectList(new LambdaQueryWrapper<UserCoupon>()
                .eq(UserCoupon::getUserId, userId));
        // 转换为UserCouponDTO列表
        List<UserCouponDTO> userCouponDTOList = userCoupons.stream().map(userCoupon -> {
            UserCouponDTO dto = new UserCouponDTO();
            // 复制UserCoupon基本属性
            dto.setId(userCoupon.getId());
            dto.setUserId(userCoupon.getUserId());
            dto.setCouponId(userCoupon.getCouponId());
            dto.setCouponCode(userCoupon.getCouponCode());
            dto.setStatus(userCoupon.getStatus());
            dto.setObtainTime(userCoupon.getObtainTime());
            dto.setUsedTime(userCoupon.getUsedTime());
            dto.setExpireTime(userCoupon.getExpireTime());
            dto.setOrderNo(userCoupon.getOrderNo());
            // 查询对应的优惠券信息
            Coupon coupon = couponMapper.selectById(userCoupon.getCouponId());
            if (coupon != null) {
                // 创建并设置CouponData
                CouponData couponData = new CouponData();
                couponData.setName(coupon.getName());
                couponData.setType(coupon.getType());
                couponData.setValue(coupon.getValue());
                couponData.setMinAmount(coupon.getMinAmount());
                dto.setCouponData(couponData);
            }
            return dto;
        }).collect(Collectors.toList());
        
        return Result.success(userCouponDTOList);
    }

    @Override
    @Transactional
    public Result getCouponByCode(List<String> couponCodes, Long userId, String orderNo) {
        if (couponCodes == null || couponCodes.isEmpty() || userId == null || orderNo == null || orderNo.isEmpty()) {
            return Result.failure(ResultCodeEnum.FAIL, "参数不完整");
        }
        
        // 查询优惠券列表
        List<Coupon> coupons = couponMapper.selectList(new LambdaQueryWrapper<Coupon>()
                .in(Coupon::getCouponCode, couponCodes));
        
        if (coupons.isEmpty()) {
            return Result.failure(ResultCodeEnum.FAIL, "未找到指定优惠券");
        }
        
        // 获取优惠券ID列表
        List<Long> couponIds = coupons.stream()
                .map(Coupon::getId)
                .collect(Collectors.toList());
        
        // 查询用户的优惠券
        List<UserCoupon> userCoupons = userCouponMapper.selectList(new LambdaQueryWrapper<UserCoupon>()
                .eq(UserCoupon::getUserId, userId)
                .in(UserCoupon::getCouponId, couponIds)
                .eq(UserCoupon::getStatus, 0)); // 状态为未使用
        
        // 检查是否所有优惠券都存在且可用
        if (userCoupons.isEmpty()) {
            return Result.failure(ResultCodeEnum.FAIL, "未找到可用的优惠券");
        }
        
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        Date currentDate = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
        
        // 创建一个Map存储优惠券ID到优惠券对象的映射，方便后续使用
        Map<Long, Coupon> couponMap = coupons.stream()
                .collect(Collectors.toMap(Coupon::getId, coupon -> coupon));
        
        // 更新用户优惠券状态
        for (UserCoupon userCoupon : userCoupons) {
            // 更新状态为已使用
            userCoupon.setStatus(1);
            // 设置订单号
            userCoupon.setOrderNo(orderNo);
            // 设置使用时间
            userCoupon.setUsedTime(now);
            
            // 更新到数据库
            userCouponMapper.updateById(userCoupon);
            
            // 创建优惠券使用记录
            Coupon coupon = couponMap.get(userCoupon.getCouponId());
            if (coupon != null) {
                CouponUsage couponUsage = new CouponUsage();
                couponUsage.setUserCouponId(userCoupon.getId());
                couponUsage.setOrderNo(orderNo);
                couponUsage.setDiscountAmount(coupon.getValue());
                couponUsage.setUsageTime(currentDate);
                couponUsage.setReversed(false);
                
                // 保存优惠券使用记录
                couponUsageMapper.insert(couponUsage);
            }
        }
        
        // 返回优惠券列表信息
        List<CouponDTO> couponDTOList = coupons.stream().map(coupon -> {
            CouponDTO dto = new CouponDTO();
            BeanUtils.copyProperties(coupon, dto);
            return dto;
        }).collect(Collectors.toList());
        
        return Result.success(couponDTOList);
    }
}
